﻿using DevExpress.XtraBars;
using System;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using System.IO;
using System.Reflection;
using DevExpress.XtraDataLayout;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using DevExpress.XtraLayout;
using DataProcess.Core.DataAccess;
using DataProcess.Core.Model;
using DataProcess.Core.Tools;
using DataProcess.Interface;
using DataProcess.Core.Enums;
using DataProcess.Core;

namespace DataProcess4Net48.Views
{
    public partial class EquipmentDetailsForm : DevExpress.XtraBars.Ribbon.RibbonForm
    {
        public Type DriveType { get; private set; }
        public Type ConfigType { get; private set; }

        public readonly string DrivePathPrefix = AppDomain.CurrentDomain.BaseDirectory + ReflectionMark.DriveMark;
        public readonly string ProcessingPathPrefix = AppDomain.CurrentDomain.BaseDirectory + ReflectionMark.ProcessingMark;

        protected virtual DbContext<Equipment> DBContext { get; set; }

        /// <summary>
        /// 数据状态
        /// </summary>
        public DataEditType DataEditType { get; private set; }

        /// <summary>
        /// 主面板上数据的RowHandle
        /// </summary>
        public int RowHandle { get; private set; }

        /// <summary>
        /// 用于更新主面板数据的委托
        /// </summary>
        public Action<int, Equipment, DataEditType> UpdateMainRow;

        /// <summary>
        /// 用于更新主面板数据的委托
        /// </summary>
        public Action<Equipment> Added;

        public Action<Equipment> Updated;

        /// <summary>
        /// 旧数据
        /// </summary>
        public Equipment OldItem { get; private set; }

        /// <summary>
        /// 新数据
        /// </summary>
        public Equipment NewItem { get; private set; }

        public EquipmentDetailsForm(Equipment item, DataEditType det, int rowHandle = -1)
        {
            DataEditType = det;
            RowHandle = rowHandle;
            DBContextInit();
            InitializeComponent();
            InitAutoGenerterComponent();
            DataProcessingFileButtonEdit.ReadOnly = true;
            DataDriveFileButtonEdit.ReadOnly = true;
            InitializeData(item, det, rowHandle);
        }

        protected virtual void DBContextInit()
        {
            DBContext = new DbContext<Equipment>();
        }

        /// <summary>
        /// 初始化数据传输通道选项卡
        /// </summary>
        private void InitDataTransmissionPages()
        {
            for (int i = NewItem.DataTransmissionConfigs.Count - 1; i >= 0; i--)
            {
                AddTransmissonTab(NewItem.DataTransmissionConfigs[i]);
            }
        }

        public virtual void InitializeData(Equipment item, DataEditType det, int rowHandle)
        {
            NewItem = new Equipment();
            if (item == null)
            {
                OldItem = new Equipment();
            }
            else
            {
                OldItem = item;
            }
            var json = item.ToJson();
            OldItem = json.FromJson<Equipment>();
            NewItem = json.FromJson<Equipment>();

            //根据数据初始化数据传输通道选项卡
            InitDataTransmissionPages();
        }

        protected void DataDetailsForm_Load(object sender, EventArgs e)
        {
            DetailsLayout.DataSource = NewItem;

            if (DataEditType == DataEditType.Modify)
            {
                SetConfigControl(Path.Combine(DrivePathPrefix, NewItem.DataDriveFile));
            }
        }

        protected void DataDetailsForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }

        protected void Save_BBI_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (OperatorInfoResult($"确定执行该操作么?点击\"确定\"会将数据{(DataEditType == DataEditType.Add ? "新增" : "更新")}至数据库!") != DialogResult.OK)
            {
                return;
            }
            DataSave();
        }

        protected void SaveAndClose_BBI_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (OperatorInfoResult($"确定执行该操作么?点击\"确定\"会将数据{(DataEditType == DataEditType.Add ? "新增" : "更新")}至数据库并关闭该窗体") != DialogResult.OK)
            {
                return;
            }
            if (DataSave(false)) DialogResult = DialogResult.OK;
        }

        protected void Reset_BBI_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (OperatorWaringResult("确定执行该操作么?点击\"确定\"将撤销所有更改!", "警告") == DialogResult.OK)
            {
                NewItem = OldItem.ToJson().FromJson<Equipment>();
                DetailsLayout.DataSource = NewItem;

                if (!string.IsNullOrEmpty(NewItem.DataDriveConfig))
                {
                    DataDriveConfigControl.DataSource = NewItem.DataDriveConfig.FromJson(ConfigType);
                }

                //删除所有的数据传输通道选项卡
                foreach (LayoutGroup page in TransmissionTabGroup.TabPages)
                {
                    var lci = (LayoutControlItem)page.Items.FirstOrDefault(it => it is LayoutControlItem);
                    if (lci == null) continue;
                    DetailsLayout.Remove(lci, true);
                }
                TransmissionTabGroup.Clear();

                //重新初始化数据传输通道选项卡
                InitDataTransmissionPages();
            }
        }

        protected bool DataSave(bool SavedMsg = true)
        {
            //判断数据驱动配置是否已经完毕
            if (!DetailsLayout.Validate()) return false;
            if (DataDriveConfigControl.DataSource is IDataDriveConfig config)
            {
                if (config.Valided())
                {
                    NewItem.DataDriveConfig = DataDriveConfigControl.DataSource.ToJson();
                }
                else
                {
                    OperatorErrorResult(config.Message);
                    return false;
                }
            }

            if (NewItem.DataTransmissionConfigs.Count != TransmissionTabGroup.TabPages.Count)
            {
                OperatorErrorResult("数据传输配置列表数量与数据传输选项卡数量不一致，请联系开发人员进行排查");
                return false;
            }

            List<IDataTransmissionConfig> configList = new List<IDataTransmissionConfig>();

            for (int i = 0; i < NewItem.DataTransmissionConfigs.Count; i++)
            {
                if (TransmissionTabGroup.TabPages[i].Tag.ToString() != NewItem.DataTransmissionConfigs[i].Id)
                {
                    OperatorErrorResult("数据传输配置列表数量与数据传输选项卡相对应的Id不同，请联系开发人员进行排查");
                    return false;
                }

                LayoutControlItem lci = (LayoutControlItem)TransmissionTabGroup.TabPages[i].Items.FirstOrDefault(it => it is LayoutControlItem);
                if (lci == null) continue;
                if (lci.Control is DataLayoutControl dlc && dlc.DataSource is IBindingList list && list.Count == 1 && list[0] is IDataTransmissionConfig transConfig)
                {
                    configList.Add(transConfig);
                    NewItem.DataTransmissionConfigs[i].DriveName = transConfig.Name;
                    NewItem.DataTransmissionConfigs[i].DriveConfig = transConfig.ToJson();
                }
            }

            //判断是否有重复的配置，判断依据
            for (int i = configList.Count - 1; i >= 0; i--)
            {
                var conf = configList[i];
                if (!conf.Valided())
                {
                    OperatorErrorResult($"数据传输配置选项卡的第[{i + 1}]个选项卡中{conf.Message}");
                    return false;
                }

                int index = -1;
                configList.RemoveAt(i);
                if (conf.BeIncluded(configList, ref index))
                {
                    OperatorWaringResult($"数据传输配置选项卡的第{index}项和第{i + 1}项关键项重合，请修改其中一项");
                    return false;
                }
            }

            switch (DataEditType)
            {
                case DataEditType.Add:
                    DataInsert(SavedMsg);
                    break;
                case DataEditType.Modify:
                    DataUpdate(SavedMsg);
                    break;
            }

            return true;
        }

        protected void DataInsert(bool SavedMsg = true)
        {
            try
            {
                if (DBContext.CurrentDb.Insert(NewItem))
                {
                    UpdateMainRow?.Invoke(RowHandle, NewItem, DataEditType);
                    Added?.Invoke(NewItem);
                    if (SavedMsg) OperatorInfoResult("保存成功!");
                    DataEditType = DataEditType.Modify;
                }
                else
                {
                    OperatorWaringResult("保存失败");
                }
            }
            catch (Exception ex)
            {
                OperatorErrorResult(ex.Message);
            }
        }

        protected void DataUpdate(bool SavedMsg = true)
        {
            try
            {
                if (DBContext.CurrentDb.Update(NewItem))
                {
                    UpdateMainRow?.Invoke(RowHandle, NewItem, DataEditType);
                    Updated?.Invoke(NewItem);
                    if (SavedMsg) OperatorInfoResult("保存成功!");
                }
                else
                {
                    OperatorWaringResult("保存失败");
                }
            }
            catch (Exception ex)
            {
                OperatorErrorResult(ex.Message);
            }
        }

        protected DialogResult OperatorWaringResult(string test, string caption = "警告")
        {
            return XtraMessageBox.Show(this, test, caption, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
        }

        protected DialogResult OperatorErrorResult(string test, string caption = "错误")
        {
            return XtraMessageBox.Show(this, test, caption, MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
        }

        protected DialogResult OperatorInfoResult(string test, string caption = "提示")
        {
            return XtraMessageBox.Show(this, test, caption, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void DetailsLayout_ItemAdded(object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(LayoutControlItem))
            {
                ((LayoutControlItem)sender).DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
            }
        }

        private void DataProcessingFileButtonEdit_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
        {
            if (sender is ButtonEdit eb)
            {
                OpenFileDialog ofd = new OpenFileDialog()
                {
                    Multiselect = false,
                    InitialDirectory = ProcessingPathPrefix,
                    Filter = $"数据处理文件({ReflectionMark.ProcessingMark}.*.dll)|{ReflectionMark.ProcessingMark}.*.dll"
                };

                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    eb.EditValue = Path.GetFileName(ofd.FileName);
                }
            }
        }

        private void DataDriveFileButtonEdit_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
        {
            if (sender is ButtonEdit eb)
            {
                OpenFileDialog ofd = new OpenFileDialog
                {
                    InitialDirectory = DrivePathPrefix,
                    Filter = $"数据处理文件({ReflectionMark.DriveMark}.*.dll)|{ReflectionMark.DriveMark}.*.dll"
                };
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    if (SetConfigControl(ofd.FileName)) eb.EditValue = Path.GetFileName(ofd.FileName);
                }
                ofd.Dispose();
            }
        }

        private bool SetConfigControl(string fileName)
        {
            Assembly assem = Assembly.LoadFile(fileName);

            //DataDriveType
            Type IDrive = typeof(IDataDrive);
            var driveTypes = assem.GetTypes().Where(it => IDrive.IsAssignableFrom(it)).ToList();
            if (driveTypes.Count == 0)
            {
                OperatorErrorResult($"{fileName}中找不到实现{IDrive.Name}接口的类型，无法使用此动态库");
                return false;
            }
            else if (driveTypes.Count > 1)
            {
                OperatorErrorResult($"{fileName}中找到多个实现{IDrive.Name}接口的类型，无法判断使用哪个类型，请联系开发人员对驱动进行更改");
                return false;
            }

            //DataConfigType
            Type IDriveConfig = typeof(IDataDriveConfig);
            var configTypes = assem.GetTypes().Where(it => IDriveConfig.IsAssignableFrom(it)).ToList();
            if (configTypes.Count == 0)
            {
                OperatorErrorResult($"{fileName}中找不到实现{IDriveConfig.Name}接口的类型，无法使用此动态库");
                return false;
            }
            else if (configTypes.Count > 1)
            {
                OperatorErrorResult($"{fileName}中找到多个实现{IDriveConfig.Name}接口的类型，无法判断使用哪个类型，请联系开发人员对驱动进行更改");
                return false;
            }

            DriveType = driveTypes[0];
            ConfigType = configTypes[0];

            object config = null;
            if (!string.IsNullOrEmpty(NewItem.DataDriveConfig))
            {
                config = NewItem.DataDriveConfig.FromJson(ConfigType);
            }

            if (config == null)
            {
                config = Activator.CreateInstance(ConfigType);
            }

            DataDriveConfigControl.DataSource = config;
            DataDriveConfigControl.RetrieveFields();
            return true;
        }

        private void DataDriveConfigControl_ControlAdded(object sender, ControlEventArgs e)
        {
            e.Control.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
            if (sender is DataLayoutControl ctrl)
            {
                ctrl.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
            }
        }


        private void DataTransmissionConfigControl_ControlAdded(object sender, ControlEventArgs e)
        {
            e.Control.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
            if (sender is DataLayoutControl ctrl)
            {
                ctrl.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
            }

            if (e.Control is TextEdit te)
            {
                string propName = te.DataBindings[0].BindingMemberInfo.BindingField;

                if (te.DataBindings[0].DataSource is IBindingList list && list.Count == 1)
                {
                    var props = list[0].GetType().GetProperties().ToDictionary(it => it.Name, it => it);

                    if (props.ContainsKey(propName))
                    {
                        var attr = (PasswordPropertyTextAttribute)props[propName].GetCustomAttributes(typeof(PasswordPropertyTextAttribute), true).FirstOrDefault();
                        if (attr != null && attr.Password)
                        {
                            te.Properties.PasswordChar = '*';
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 加载数据传输通道
        /// </summary>
        private void InitAutoGenerterComponent()
        {
            List<LinkPersistInfo> infoList = new List<LinkPersistInfo>();
            ((ISupportInitialize)(ribbon)).BeginInit();
            foreach (var path in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + $@"{ReflectionMark.TransmissionMark}", $"{ReflectionMark.TransmissionMark}.*.dll"))
            {
                string attrContext = string.Empty;
                var assembly = Assembly.LoadFile(path);
                Type ITrans = typeof(IDataTransmission);

                if (!assembly.GetTypes().Any(it => ITrans.IsAssignableFrom(it)))
                {
                    continue;
                }

                object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
                if (attributes.Length != 0)
                {
                    attrContext = ((AssemblyDescriptionAttribute)attributes[0]).Description;
                }
                else
                {
                    attributes = assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
                    if (attributes.Length != 0)
                    {
                        attrContext = ((AssemblyTitleAttribute)attributes[0]).Title;
                    }
                }

                if (string.IsNullOrEmpty(attrContext)) continue;

                BarButtonItem bbi = CreateButtonItem(attrContext, Path.GetFileName(path));
                ribbon.Items.Add(bbi);
                infoList.Add(new LinkPersistInfo(bbi));
            }

            if (infoList.Count > 0)
            {
                AddTransmisson.LinksPersistInfo.AddRange(infoList.ToArray());
            }
            ((ISupportInitialize)(ribbon)).EndInit();
        }

        /// <summary>
        /// 根据获取的数据传输通道增加下拉列表
        /// </summary>
        /// <param name="desc"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private BarButtonItem CreateButtonItem(string desc, string fileName)
        {
            var BBI = new BarButtonItem
            {
                Caption = desc,
                Tag = fileName
            };
            BBI.ItemClick += new ItemClickEventHandler(CustomBBI_ItemClick);
            return BBI;
        }

        /// <summary>
        /// 增加数据传输方式
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CustomBBI_ItemClick(object sender, ItemClickEventArgs e)
        {
            var config = new DataTransmissionConfig { DriveType = e.Item.Caption, DriveFileName = (string)e.Item.Tag, DriveConfig = string.Empty };
            NewItem.DataTransmissionConfigs.Add(config);
            AddTransmissonTab(config, false);
        }

        /// <summary>
        /// 增加数据传输配置选项卡
        /// </summary>
        /// <param name="title"></param>
        /// <param name="assmPath"></param>
        /// <param name="dtc"></param>
        private void AddTransmissonTab(DataTransmissionConfig dtc, bool init = true)
        {
            DataLayoutControl control = new DataLayoutControl()
            {
                Dock = DockStyle.Fill,
                AllowCustomization = false
            };

            control.ControlAdded += DataTransmissionConfigControl_ControlAdded;

            if (!SetTransmissionConfig(control, dtc.DriveFileName, dtc))
            {
                NewItem.DataTransmissionConfigs.Remove(dtc);
                return;
            }

            string tabPageTitle = $"{dtc.DriveType}{(string.IsNullOrEmpty(dtc.DriveName) ? "" : $"({dtc.DriveName})")}";
            LayoutControlGroup lcg = new LayoutControlGroup
            {
                CustomizationFormText = tabPageTitle,
                GroupStyle = DevExpress.Utils.GroupStyle.Card,
                Text = tabPageTitle,
                Tag = dtc.Id
            };

            lcg.Items.AddRange(new BaseLayoutItem[] { new LayoutControlItem() { Control = control, TextVisible = false } });

            if (init) TransmissionTabGroup.InsertTabPage(0, lcg);
            else TransmissionTabGroup.AddTabPage(lcg);
        }

        private bool SetTransmissionConfig(DataLayoutControl dataLayoutControl, string fileName, DataTransmissionConfig dtc)
        {
            if (string.IsNullOrEmpty(fileName)) return false;
            string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + ReflectionMark.TransmissionMark, fileName);
            if (!File.Exists(path)) return false;

            Assembly assem = Assembly.LoadFile(path);
            //IDataTransmission
            Type ITransmission = typeof(IDataTransmission);
            var transmissionTypes = assem.GetTypes().Where(it => ITransmission.IsAssignableFrom(it)).ToList();
            if (transmissionTypes.Count == 0)
            {
                OperatorErrorResult($"{path}中找不到实现{ITransmission.Name}接口的类型，无法使用此动态库");
                return false;
            }
            else if (transmissionTypes.Count > 1)
            {
                OperatorErrorResult($"{path}中找到多个实现{ITransmission.Name}接口的类型，无法判断使用哪个类型，请联系开发人员对驱动进行更改");
                return false;
            }

            //IDataTransmissionConfig
            Type ITransmissionConfig = typeof(IDataTransmissionConfig);
            var configTypes = assem.GetTypes().Where(it => ITransmissionConfig.IsAssignableFrom(it)).ToList();
            if (configTypes.Count == 0)
            {
                OperatorErrorResult($"{path}中找不到实现{ITransmissionConfig.Name}接口的类型，无法使用此动态库");
                return false;
            }
            else if (configTypes.Count > 1)
            {
                OperatorErrorResult($"{path}中找到多个实现{ITransmissionConfig.Name}接口的类型，无法判断使用哪个类型，请联系开发人员对驱动进行更改");
                return false;
            }

            DriveType = transmissionTypes[0];
            ConfigType = configTypes[0];

            object config = null;
            if (!string.IsNullOrEmpty(dtc.DriveConfig))
            {
                config = dtc.DriveConfig.FromJson(ConfigType);
            }

            if (config == null)
            {
                config = Activator.CreateInstance(ConfigType);
            }

            var bindType = typeof(BindingList<>).MakeGenericType(ConfigType);
            var bindindlist = Activator.CreateInstance(bindType);
            bindType.GetMethod("Add").Invoke(bindindlist, new object[] { config });

            dataLayoutControl.DataSource = bindindlist;
            dataLayoutControl.RetrieveFields();
            return true;
        }

        private void DelTransmisson_ItemClick(object sender, ItemClickEventArgs e)
        {
            string key = TransmissionTabGroup.SelectedTabPage.Tag.ToString();

            var lci = (LayoutControlItem)TransmissionTabGroup.SelectedTabPage.Items.FirstOrDefault(it => it is LayoutControlItem);
            if (lci == null) return;

            DetailsLayout.Remove(lci, true);

            TransmissionTabGroup.RemoveTabPage(TransmissionTabGroup.SelectedTabPage);

            NewItem.DataTransmissionConfigs.RemoveAll(it => it.Id == key);
        }
    }
}